package com.eastfair.questionnaire.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.questionnaire.dto.QuestionnaireExcelDTO;
import com.eastfair.questionnaire.dto.QuestionnaireExcelResultDTO;
import com.eastfair.questionnaire.entity.Answer;
import com.eastfair.questionnaire.entity.Question;
import com.eastfair.questionnaire.entity.Questionnaire;
import com.eastfair.questionnaire.service.AnswerService;
import com.eastfair.questionnaire.service.QuestionService;
import com.eastfair.questionnaire.service.QuestionnaireImportService;
import com.eastfair.questionnaire.service.QuestionnaireService;
import com.eastfair.questionnaire.vo.AnswerVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @ClassName QuestionnaireImportServiceImpl
 * @Description TODO
 * @Author yuwx
 * @Date 2021/9/6 13:30
 * @Version 1.0
 **/
@Slf4j
@Service
public class QuestionnaireImportServiceImpl implements QuestionnaireImportService {
    private ProjectCoreServiceFeign projectCoreServiceFeign;
    private AnswerService answerService;
    private QuestionnaireService questionnaireService;
    private QuestionService questionService;

    @Autowired
    public QuestionnaireImportServiceImpl(ProjectCoreServiceFeign projectCoreServiceFeign, AnswerService answerService, QuestionnaireService questionnaireService, QuestionService questionService) {
        this.projectCoreServiceFeign = projectCoreServiceFeign;
        this.answerService = answerService;
        this.questionnaireService = questionnaireService;
        this.questionService = questionService;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchSave(QuestionnaireExcelResultDTO questionnaireExcelResultDTO) {
        questionnaireService.save(questionnaireExcelResultDTO.getQuestionnaire());
        questionService.saveBatch(questionnaireExcelResultDTO.getQuestionList());
        answerService.saveBatch(questionnaireExcelResultDTO.getAnswerList());
    }

    /**
     * Description 转换excel为答案和问题列表
     *
     * @param projectId
     * @param questionnaireExcelList
     * @return void
     * @Date 10:47 2021/9/7
     * @Author yuwx
     **/
    @Override
    public QuestionnaireExcelResultDTO convertQuestionnaire(Long projectId, List<QuestionnaireExcelDTO> questionnaireExcelList) {
        if (CollectionUtil.isEmpty(questionnaireExcelList)) {
            return null;
        }
        final Questionnaire questionnaire = convertQuestionnaire(projectId, questionnaireExcelList.get(0));
        final List<Question> questionList = new ArrayList<>();
        final Map<Integer, Question> questionSequenceMap = new HashMap<>();
        final Map<String, Answer> parentAnswerMap = new HashMap<>();
        final List<Answer> answerList = new ArrayList<>();
        questionnaireExcelList.stream().forEach(questionnaireExcel -> {
            //转换问题
            if (Objects.isNull(questionSequenceMap.get(questionnaireExcel.getQuestionSequence()))) {
                Question question = convertQuestion(projectId, questionnaire, questionnaireExcel);
                questionSequenceMap.put(questionnaireExcel.getQuestionSequence(), question);
                questionList.add(question);
            }

            Answer parentAnswer;
            //如果是新的一级节点，转换+填充
            if (Objects.isNull(parentAnswerMap.get(getAnswerMapKey(questionnaireExcel)))) {
                parentAnswer = convertParentAnswer(projectId, questionSequenceMap, questionnaireExcel);
                if (Objects.isNull(parentAnswer)) {
                    return;
                }
                if (BusinessConstant.YES != parentAnswer.getIsLeaf()) {
                    parentAnswerMap.put(getAnswerMapKey(questionnaireExcel), parentAnswer);
                }
                answerList.add(parentAnswer);
            }
            parentAnswer = parentAnswerMap.get(getAnswerMapKey(questionnaireExcel));
            //转换叶子节点 + 填充 + 临时处理跳题
            Answer subAnswer = convertSubAnswer(projectId, parentAnswer, questionnaireExcel);
            if (Objects.isNull(subAnswer)) {
                return;
            }
            answerList.add(subAnswer);
        });
        setQuestionNextId(questionList);
        setAnswerNextQuestionId(questionList, answerList);
        orderAnswer(answerList);

        return new QuestionnaireExcelResultDTO(questionnaire, questionList, answerList);
    }

    /**
     * Description 答案增加序号
     *
     * @param answerList
     * @return void
     * @Date 10:44 2021/9/7
     * @Author yuwx
     **/
    private void orderAnswer(List<Answer> answerList) {
        Answer previousParentAnswer = new Answer();
        Answer previousSubAnswer = new Answer();
        Answer currentAnswer;
        for (int i = 0; i < answerList.size(); i++) {
            currentAnswer = answerList.get(i);
            if (answerService.isTopAnswer(BeanUtil.toBean(currentAnswer, AnswerVO.class))) {
                if (!currentAnswer.getQuestionId().equals(previousParentAnswer.getQuestionId())) {
                    currentAnswer.setSequence(1);
                } else {
                    currentAnswer.setSequence(previousParentAnswer.getSequence() + 1);
                }
                previousParentAnswer = currentAnswer;
            } else if (answerService.isLeafAnswer(BeanUtil.toBean(currentAnswer, AnswerVO.class))) {
                if (!currentAnswer.getParentAnswerId().equals(previousSubAnswer.getParentAnswerId())) {
                    currentAnswer.setSequence(1);
                } else {
                    currentAnswer.setSequence(previousSubAnswer.getSequence() + 1);
                }
                previousSubAnswer = currentAnswer;
            } else {
                log.error("导入异常，出现非一级、二级节点的情况");
            }
        }
    }

    /**
     * Description 设置答案跳题（前面临时把answer的下一题设置为问题的序号，这里替换）
     *
     * @param questionList
     * @param answerList
     * @return void
     * @Date 10:40 2021/9/7
     * @Author yuwx
     **/
    private void setAnswerNextQuestionId(List<Question> questionList, List<Answer> answerList) {
        Map<Integer, Question> questionSequenceMap = questionList.stream().collect(Collectors.toMap(Question::getSequence, Question -> Question));
        Map<Long, Question> questionIdMap = questionList.stream().collect(Collectors.toMap(Question::getId, Question -> Question));
        answerList.stream().forEach(answer -> {
            if (!Objects.isNull(answer.getNextQuestionId())) {
                Question nextQuestion = questionSequenceMap.get(answer.getNextQuestionId().intValue());
                answer.setNextQuestionId(nextQuestion.getId());
            } else {
                answer.setNextQuestionId(questionIdMap.get(answer.getQuestionId()).getNextQuestionId());
            }
        });

    }

    /**
     * Description 答案跳题设置
     *
     * @param questionList
     * @return void
     * @Date 10:37 2021/9/7
     * @Author yuwx
     **/
    private void setQuestionNextId(List<Question> questionList) {
        final AtomicInteger nextQuestionIndex = new AtomicInteger(1);
        questionList.stream().sorted(Comparator.comparing(Question::getSequence)).forEach(question -> {
            if (nextQuestionIndex.get() >= questionList.size()) {
                return;
            }
            question.setNextQuestionId(questionList.get(nextQuestionIndex.getAndIncrement()).getId());
        });
    }

    /**
     * Description 转换为问卷
     *
     * @param projectId
     * @param questionnaireExcelDTO
     * @return com.eastfair.questionnaire.entity.Questionnaire
     * @Date 10:08 2021/9/7
     * @Author yuwx
     **/
    private Questionnaire convertQuestionnaire(Long projectId, QuestionnaireExcelDTO questionnaireExcelDTO) {
        Questionnaire questionnaire = Questionnaire.builder()
                .id(DefaultUidGenerator.getUidOfProjectId(projectId))
                .projectId(projectId)
                .name(questionnaireExcelDTO.getQuestionnaireName())
                .build();
        return questionnaire;
    }

    /**
     * Description 行数据转为为问题
     *
     * @param projectId
     * @param questionnaire
     * @param questionnaireExcelDTO
     * @return com.eastfair.questionnaire.entity.Question
     * @Date 10:22 2021/9/7
     * @Author yuwx
     **/
    private Question convertQuestion(Long projectId, Questionnaire questionnaire, QuestionnaireExcelDTO questionnaireExcelDTO) {
        Question question = Question.builder()
                .id(DefaultUidGenerator.getUidOfProjectId(projectId))
                .projectId(projectId)
                .questionnaireId(questionnaire.getId())
                .name(questionnaireExcelDTO.getQuestionName())
                .aliasName(questionnaireExcelDTO.getQuestionAliasName())
                .enName(questionnaireExcelDTO.getQuestionEnName())
                .enAliasName(questionnaireExcelDTO.getQuestionEnAliasName())
                .questionType(questionnaireExcelDTO.getQuestionType().name())
                .isRequired(BooleanUtil.toInteger(questionnaireExcelDTO.getIsRequire()))
                .selectLower(questionnaireExcelDTO.getSelectLower())
                .selectUpper(questionnaireExcelDTO.getSelectUpper())
                .sequence(questionnaireExcelDTO.getQuestionSequence())
                .build();
        return question;
    }

    /**
     * Description 转换行数据的父节点
     *
     * @param projectId
     * @param questionSequenceMap
     * @param questionnaireExcelDTO
     * @return com.eastfair.questionnaire.entity.Answer
     * @Date 10:25 2021/9/7
     * @Author yuwx
     **/
    private Answer convertParentAnswer(Long projectId, Map<Integer, Question> questionSequenceMap, QuestionnaireExcelDTO questionnaireExcelDTO) {
        Boolean exist = existAnswer(questionnaireExcelDTO);
        if (!exist) {
            return null;
        }
        Boolean existSubAnswer = existSubAnswer(questionnaireExcelDTO);
        Answer answer = Answer.builder()
                .id(DefaultUidGenerator.getUidOfProjectId(projectId))
                .projectId(projectId)
                .name(questionnaireExcelDTO.getAnswerName())
                .aliasName(questionnaireExcelDTO.getAnswerAliasName())
                .enName(questionnaireExcelDTO.getQuestionEnName())
                .enAliasName(questionnaireExcelDTO.getAnswerEnAliasName())
                .isLeaf(BooleanUtil.toInteger(!existSubAnswer))
                .isInput(existSubAnswer ? BusinessConstant.NO : BooleanUtil.toInteger(questionnaireExcelDTO.getIsAnswerInput()))
                .nextQuestionId(existSubAnswer ? null : questionnaireExcelDTO.getNextQuestionSequence())
                .questionId(questionSequenceMap.get(questionnaireExcelDTO.getQuestionSequence()).getId())
                .build();
        return answer;
    }

    /**
     * Description 转换叶子节点
     * *********************注意：下一题临时填充的是问题的序号*********************
     *
     * @param projectId
     * @param parentAnswer
     * @param questionnaireExcelDTO
     * @return com.eastfair.questionnaire.entity.Answer
     * @Date 10:33 2021/9/7
     * @Author yuwx
     **/
    private Answer convertSubAnswer(Long projectId, Answer parentAnswer, QuestionnaireExcelDTO questionnaireExcelDTO) {
        Boolean exist = existSubAnswer(questionnaireExcelDTO);
        if (!exist) {
            return null;
        }
        Answer subAnswer = Answer.builder()
                .id(DefaultUidGenerator.getUidOfProjectId(projectId))
                .projectId(projectId)
                .name(questionnaireExcelDTO.getSubAnswerName())
                .aliasName(questionnaireExcelDTO.getSubAnswerAliasName())
                .enName(questionnaireExcelDTO.getSubAnswerEnName())
                .enAliasName(questionnaireExcelDTO.getSubAnswerEnAliasName())
                .isLeaf(BusinessConstant.YES)
                .isInput(BooleanUtil.toInteger(questionnaireExcelDTO.getIsAnswerInput()))
                .nextQuestionId(questionnaireExcelDTO.getNextQuestionSequence())
                .questionId(parentAnswer.getQuestionId())
                .parentAnswerId(parentAnswer.getId())
                .build();
//                .sequence(qu)
        return subAnswer;

    }

    /**
     * Description 父节点非空校验
     *
     * @param questionnaireExcelDTO
     * @return java.lang.Boolean
     * @Date 10:28 2021/9/7
     * @Author yuwx
     **/
    private Boolean existAnswer(QuestionnaireExcelDTO questionnaireExcelDTO) {
        return !StrUtil.isAllBlank(questionnaireExcelDTO.getAnswerName(),
                questionnaireExcelDTO.getAnswerAliasName(),
                questionnaireExcelDTO.getAnswerEnName(),
                questionnaireExcelDTO.getAnswerEnAliasName());
    }

    /**
     * Description 叶子节点非空校验
     *
     * @param questionnaireExcelDTO
     * @return java.lang.Boolean
     * @Date 10:29 2021/9/7
     * @Author yuwx
     **/
    private Boolean existSubAnswer(QuestionnaireExcelDTO questionnaireExcelDTO) {
        return !StrUtil.isAllBlank(questionnaireExcelDTO.getSubAnswerName(),
                questionnaireExcelDTO.getSubAnswerAliasName(),
                questionnaireExcelDTO.getSubAnswerEnName(),
                questionnaireExcelDTO.getSubAnswerEnAliasName());
    }

    /**
     * Description 答案父节点key , 问题Name + 答案Name
     *
     * @param questionnaireExcelDTO
     * @return java.lang.String
     * @Date 10:24 2021/9/7
     * @Author yuwx
     **/
    private String getAnswerMapKey(QuestionnaireExcelDTO questionnaireExcelDTO) {
        return questionnaireExcelDTO.getQuestionName() + questionnaireExcelDTO.getAnswerName();
    }

}
